/*********************************************************************************************************************
 * COPYRIGHT NOTICE
 * Copyright (c) 2018,逐飞科技
 * All rights reserved.
 * 技术讨论QQ群：	一群：179029047(已满)
 *					二群：244861897(已满)
 *					三群：824575535
 *
 * 以下所有内容版权均属逐飞科技所有，未经允许不得用于商业用途，
 * 欢迎各位使用并传播本程序，修改内容时必须保留逐飞科技的版权声明。
 *
 * @file			seekfree_ms5611.c
 * @company			成都逐飞科技有限公司
 * @author			逐飞科技(QQ3184284598)
 * @version			查看doc内version文件 版本说明
 * @Software		IAR 8.3 or MDK 5.24
 * @Taobao			https://seekfree.taobao.com/
 * @date			2020-03-25
 * @note			本文件作为IOT开发板seekfree_ms5611传感器API
 ********************************************************************************************************************/
#include "seekfree_ms5611.h"
#include "zf_utick.h"

static uint16_t ms5611_read_buffer[8][8];
static double ms5611_temperature;
static double ms5611_pressure;

//-------------------------------------------------------------------------------------------------------------------
//  @brief      初始化MS5611
//  @param      Index			使用的 FlexCOMM 端口
//  @return     void			
//  @since      v1.0
//-------------------------------------------------------------------------------------------------------------------
#ifdef IOT_BOARD
void ms5611_init (iot_flexcomm_index_list Index)
#else
void ms5611_init (flexcomm_index_list Index)
#endif
{
	i2c_master_config_t iic_ms5611_config;													// 定义一个 Flex COMM 配置结构体
	zf_iic_master_get_default_config( &iic_ms5611_config);									// 获取默认设置
#ifdef IOT_BOARD
	iot_flexcomm_init(Index, FLEX_COMM_IIC_MASTER, &iic_ms5611_config);
#else
	zf_flexcomm_init((flexcomm_index_list)Index, FLEX_COMM_IIC_MASTER, &iic_ms5611_config);
#endif

	ms5611_send_cmd(Index, MS5xxx_CMD_RESET);
	delay_ms(1);
	ms5611_read_prom(Index);
}

#ifdef IOT_BOARD
void ms5611_send_cmd (iot_flexcomm_index_list Index,uint8_t cmd)
#else
void ms5611_send_cmd (flexcomm_index_list Index,uint8_t cmd)
#endif
{
	uint8_t cmd_buff = cmd;

	I2C_MasterStart(iic_index[Index], I2C_MS5611, kI2C_Write);
	I2C_MasterWriteBlocking(iic_index[Index], &cmd_buff, 1, kI2C_TransferDefaultFlag);
	I2C_MasterStop(iic_index[Index]);
}

#ifdef IOT_BOARD
void ms5611_read_prom (iot_flexcomm_index_list Index)
#else
void ms5611_read_prom (flexcomm_index_list Index)
#endif
{
	uint8_t loop_count = 0;
	uint8_t read_buffer[2] = {0, 0};
	ms5611_send_cmd(Index, MS5xxx_CMD_RESET);
	delay_ms(3);

	for(loop_count = 0; loop_count < 8; loop_count++)
	{
		ms5611_send_cmd(Index, MS5xxx_CMD_PROM_RD+2*loop_count);

		I2C_MasterStart(iic_index[Index], I2C_MS5611, kI2C_Read);
		I2C_MasterReadBlocking(iic_index[Index], read_buffer, 2, kI2C_TransferDefaultFlag);
		I2C_MasterStop(iic_index[Index]);

		ms5611_read_buffer[Index][loop_count] |= ((uint16_t)read_buffer[0] << 8);
		ms5611_read_buffer[Index][loop_count] |= ((uint16_t)read_buffer[1] & 0x00ff);
	}
}

#ifdef IOT_BOARD
uint16_t ms5611_calc_crc4 (iot_flexcomm_index_list Index)
#else
uint16_t ms5611_calc_crc4 (flexcomm_index_list Index)
#endif
{
	int cnt;							// simple counter
	uint16_t n_rem;					// CRC remainder
	uint16_t crc_read;				// original value of the CRC
	uint16_t l_pol = 0x30;
	uint8_t n_bit;

	l_pol = (l_pol << 8) & 0xf000;	// shift bits and apply mask
	n_rem = 0x0000;

	crc_read = ms5611_read_buffer[Index][7];					// save read RCR
	ms5611_read_buffer[Index][7] = (0xFF00 & (ms5611_read_buffer[Index][7]));	// CRC byte is replaced by 0
	for (cnt = 0; cnt < 16; cnt++)	// operation is performed on bytes
	{// choose LSB or MSB
		if (cnt % 2 == 1)
			n_rem ^= (unsigned short) ((ms5611_read_buffer[Index][cnt >> 1]) & 0x00FF);
		else
			n_rem ^= (unsigned short) ((ms5611_read_buffer[Index][ cnt >> 1 ] >> 8) & 0x00FF);

		for(n_bit = 8; n_bit > 0; n_bit--)
		{
			if(n_rem & (0x8000))
			{
				n_rem = (n_rem << 1) ^ l_pol;
			}
			else
			{
				n_rem = (n_rem << 1);
			}
		}
	}
	ms5611_read_buffer[Index][7] = crc_read;
	n_rem = (0x000F & (n_rem >> 12)); // final 4-bit remainder is CRC code
	return n_rem;
}

#ifdef IOT_BOARD
uint16_t ms5611_read_crc4 (iot_flexcomm_index_list Index)
#else
uint16_t ms5611_read_crc4 (flexcomm_index_list Index)
#endif
{
	return (0x000F &(ms5611_read_buffer[Index][7]));
}

#ifdef IOT_BOARD
uint16_t ms5611_read_databuffer (iot_flexcomm_index_list Index, uint8_t index)
#else
uint16_t ms5611_read_databuffer (flexcomm_index_list Index, uint8_t index)
#endif
{
	return ms5611_read_buffer[Index][index % 8];
}

#ifdef IOT_BOARD
uint32_t ms5611_read_adc (iot_flexcomm_index_list Index, uint8_t cmd)
#else
uint32_t ms5611_read_adc (flexcomm_index_list Index, uint8_t cmd)
#endif
{
	uint32_t value = 0x00000000;
	uint8_t func_data_buffer[3];

	ms5611_send_cmd(Index, MS5xxx_CMD_ADC_CONV + cmd);
	switch (cmd & 0x0f)
	{
		case MS5xxx_CMD_ADC_256 : 
			delay_us(900);
			break;
		case MS5xxx_CMD_ADC_512 :
			delay_ms(3);
			break;
		case MS5xxx_CMD_ADC_1024:
			delay_ms(4);
			break;
		case MS5xxx_CMD_ADC_2048:
			delay_ms(6);
			break;
		case MS5xxx_CMD_ADC_4096:
			delay_ms(10);
			break;
	}
	ms5611_send_cmd(Index, MS5xxx_CMD_ADC_READ);
	I2C_MasterStart(iic_index[Index], I2C_MS5611, kI2C_Read);
	I2C_MasterReadBlocking(iic_index[Index], func_data_buffer, 3, kI2C_TransferDefaultFlag);
	I2C_MasterStop(iic_index[Index]);

	value |= (((uint32_t)func_data_buffer[0] << 16) & 0x00FF0000);
	value |= (((uint32_t)func_data_buffer[1] << 8) & 0x0000FF00);
	value |= (((uint32_t)func_data_buffer[2]) & 0x000000FF);
	return value;
}

#ifdef IOT_BOARD
void ms5611_read_out (iot_flexcomm_index_list Index)
#else
void ms5611_read_out (flexcomm_index_list Index)
#endif
{
	uint32_t data1, data2;
	double dT, OFF, SENS;
	double T2, OFF2, SENS2;

	data2 = ms5611_read_adc(Index, MS5xxx_CMD_ADC_D2+MS5xxx_CMD_ADC_4096);
	data1 = ms5611_read_adc(Index, MS5xxx_CMD_ADC_D1+MS5xxx_CMD_ADC_4096);

	dT					=	data2 - ((uint32_t)ms5611_read_buffer[Index][5] << 8);
	OFF					=	((uint32_t)ms5611_read_buffer[Index][2] << 16) + (dT*ms5611_read_buffer[Index][4] / 0x80);
	SENS				=	((uint32_t)ms5611_read_buffer[Index][1] << 15) + (dT*ms5611_read_buffer[Index][3] / 0x100);
	ms5611_temperature	=	(2000 + (dT * ms5611_read_buffer[Index][6] / 0x800000));
	ms5611_pressure		=	(((data1 * SENS) / 0x200000 - OFF) / 0x8000);

	if(ms5611_temperature < 2000)
	{
		T2				=	dT * dT / 0x80000000;
		OFF2			=	5 * (ms5611_temperature - 2000) * (ms5611_temperature - 2000) / 0x02;
		SENS2			=	5 * (ms5611_temperature - 2000) * (ms5611_temperature - 2000) / 0x04;
		if(ms5611_temperature < -1500)
		{
			OFF2		+=	7 * (ms5611_temperature + 1500) * (ms5611_temperature + 1500);
			SENS2		+=	11 * (ms5611_temperature + 1500) * (ms5611_temperature + 1500) / 0x02;
		}
	}

	ms5611_temperature	-=	T2;
	OFF					-=	OFF2;
	SENS				-=	SENS2;
	ms5611_pressure		=	(((data1 * SENS) / 0x200000 - OFF) / 0x8000);
}

#ifdef IOT_BOARD
double ms5611_get_temperature (iot_flexcomm_index_list Index)
#else
double ms5611_get_temperature (flexcomm_index_list Index)
#endif
{
	ms5611_read_out(Index);
	return ms5611_temperature;
}

#ifdef IOT_BOARD
double ms5611_get_pressure (iot_flexcomm_index_list Index)
#else
double ms5611_get_pressure (flexcomm_index_list Index)
#endif
{
	ms5611_read_out(Index);
	return ms5611_pressure;
}
